//
//  ModelViewController.swift
//  Alamofire
//
//  Created by chenyusen on 2018/3/20.
//

import UIKit

open class ModelViewController: BaseViewController, DataModelDelegateCompatible {
    struct StateFlag {
        var isModelDidRefreshInvalid = false
        var isModelWillLoadInvalid = false
        var isModelDidLoadInvalid = false
        var isModelDidLoadFirstTimeInvalid = false
        var isModelDidShowFirstTimeInvalid = false
        var isViewInvalid = false
        var isViewSuspended = false
        var isUpdatingView = false
        var isShowingEmpty = false
        var isShowingLoading = false
        var isShowingModel = false
        var isShowingError = false
    }
    
    private var _model: DataModelCompatible?
    private var modelError: Error?
 
    open var model: DataModelCompatible {
        get {
            if _model == nil {
                createModel()
            }
            if _model == nil {
                createInterstitialModel()
            }
            return _model!
        }
        
        set {
            if newValue !== _model {
                _model?.delegates.remove(self)
                _model = newValue
                _model?.delegates.add(self)
                modelError = nil

                if _model != nil {
                    flag.isModelWillLoadInvalid = false
                    flag.isModelDidLoadInvalid = false
                    flag.isModelDidLoadFirstTimeInvalid = false
                    flag.isModelDidShowFirstTimeInvalid = true
                }
            }
            
            refresh()

        }
    }
    
    var flag = StateFlag()

    public var errorView: StateView?
    
    var isShowDefaultLoadingStates: Bool = false
    
    public required init(query: [AnyHashable : Any]?) {
        super.init(query: query)
        flag.isViewInvalid = true
    }
    
    required public init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    deinit {
        _model?.delegates.remove(self)
    }
    
    
    
    // MARK: - View Life Cycle
    open override func viewDidLoad() {
        super.viewDidLoad()
        
        
        // Do any additional setup after loading the view.
    }
    
    open override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        updateView()
    }
    
    
    open override func didReceiveMemoryWarning() {
        if hasViewAppeared && !isViewAppearing {
            super.didReceiveMemoryWarning()
            refresh()
        } else {
            super.didReceiveMemoryWarning()
        }
    }
    
    /// 刷新模型状态, 并在必要时加载新数据
    public func refresh() {
        flag.isViewInvalid = true
        flag.isModelDidRefreshInvalid = true
        
        let loading = model.isLoading
        let loaded = model.isLoaded
        
        // 刷新
        // 如果没有加载过, 则more = false
        if !loading && !loaded && shouldLoad() {
            model.load(more: false)
        } else if !loading && loaded && shouldReload() {
            model.load(more: false)
        } else if !loading && shouldLoadMore() {
            model.load(more: true)
        } else {
            flag.isModelDidLoadInvalid = true
            if isViewAppearing {
                updateView()
            }
        }
    }
    
    func beginUpdates() {
        flag.isViewSuspended = true
    }
    
    func endUpdates() {
        flag.isViewSuspended = false
        updateView()
    }
    
    func invalidateView() {
        flag.isViewInvalid = true
        if isViewAppearing {
            updateView()
        }
    }
    
    private func updateView() {
        if flag.isViewInvalid && !flag.isViewSuspended && !flag.isUpdatingView {
            flag.isUpdatingView = true
            
            let _ = model // 确保model已经创建
            let _ = view // 确保view已经创建
            
            updateViewStates()
            
            flag.isViewInvalid = false
            flag.isUpdatingView = false
            
            reloadIfNeeded()
        }
    }

    
    /// 创建当前驱动当前控制器的model, 子类需要重写该方法
    open func createModel() {}
    
    
    /// 销毁model并生成新的
    public func invalidateModel() {
        let wasModelCreated = isModelCreated()
        resetViewStates()
        _model?.delegates.removeAllObjects()
        _model = nil
        
        if wasModelCreated {
            let _ = model
        }
    }
    
    open func createInterstitialModel() {
        model = DefaultDataModel()
    }
    
    
    
    /// 判断当前控制器的model是否已经创建完毕
    ///
    /// - Returns: 是否创建完毕
    open func isModelCreated() -> Bool {
        return _model != nil
    }
    
    
    /// 指示是否需要对当前model进行数据加载, 不要直接调用, 如有必要子类需要重写该方法
    ///
    /// - Returns: 是否需要加载数据
    open func shouldLoad() -> Bool {
        return !model.isLoaded
    }
    
    
    /// 指示是否需要对当前model进行数据重新加载, 不要直接调用, 如有必要子类需要重写该方法
    ///
    /// - Returns: 是否需要重新调用
    open func shouldReload() -> Bool {
        return modelError == nil && model.isOutdated
    }
    
    
    /// 指示需要对当前model进行更多数据加载, 不要直接调用, 如有必要,自雷需要重写该方法
    ///
    /// - Returns: 是否需要加载更多
    open func shouldLoadMore() -> Bool {
        return false
    }
    
    
    /// 测试是否已经可以显示model数据驱动的试图
    /// 模型加载后,调用此方法来测试是否设置model具有可现实的内容. 如果返回false,则showEmpty将会调用, 如果返回true, 则showModel将会调用
    ///
    /// - Returns: 是否可现实model驱动的试图
    open func canShowModel() -> Bool {
        return true
    }
    
    
    /// 重新从model中加载数据
    public func reload() {
        flag.isViewInvalid = true
        model.load(more: false)
    }

    
    /// 当数据已经过期,或则上次请求失败时, 重新从model中加载数据
    public func reloadIfNeeded() {
        if shouldReload() && !model.isLoading {
            reload()
        }
    }
    
    
    /// 重置所有状态
    private func resetViewStates() {
        if flag.isShowingLoading {
            showLoading(false)
            flag.isShowingLoading = false
        }
        
        if flag.isShowingModel {
            showModel(false)
            flag.isShowingModel = false
        }
        
        if flag.isShowingError {
            showError(false)
            flag.isShowingError = false
        }
        
        if flag.isShowingEmpty {
            showEmpty(false)
            flag.isShowingEmpty = false
        }
    }
    
    /// 更新试图状态
    private func updateViewStates() {
        if flag.isModelDidRefreshInvalid {
            didRefreshModel()
            flag.isModelDidRefreshInvalid = false
        }
        if flag.isModelWillLoadInvalid {
            willLoadModel()
            flag.isModelWillLoadInvalid = false
        }
        if flag.isModelDidLoadInvalid {
            didLoadModel(isFirstTime: flag.isModelDidLoadFirstTimeInvalid)
            flag.isModelDidLoadInvalid = false
            flag.isModelDidLoadFirstTimeInvalid = false
            flag.isShowingModel = false
        }
        
        var showModelFlag = false
        var showLoadingFlag = false
        var showErrorFlag = false
        var showEmptyFlag = false
        
        if (_model != nil ? _model!.isLoaded : false) || !shouldLoad() {
            if canShowModel() {
                showModelFlag = !flag.isShowingModel
                flag.isShowingModel = true
            } else {
                if flag.isShowingModel {
                    showModel(false)
                    flag.isShowingModel = false
                }
            }
        } else {
            if flag.isShowingModel {
                showModel(false)
                flag.isShowingModel = false
            }
        }
        
        // 如果model正在加载
        if (_model != nil ? _model!.isLoading : false) {
            showLoadingFlag = !flag.isShowingLoading
            flag.isShowingLoading = true
        } else {
            if flag.isShowingLoading {
                showLoading(false)
                flag.isShowingLoading = false
            }
        }
        
        // 如果有model错误
        if modelError != nil {
            showErrorFlag = !flag.isShowingError
            flag.isShowingError = true
        } else {
            if flag.isShowingError {
                showError(false)
                flag.isShowingError = false
            }
        }
        
        // 如果模型是否为空
        if !flag.isShowingLoading && !flag.isShowingModel && !flag.isShowingError {
            showEmptyFlag = !flag.isShowingEmpty
            flag.isShowingEmpty = true
        } else {
            if flag.isShowingEmpty {
                showEmpty(false)
                flag.isShowingEmpty = false
            }
        }
        
        if showModelFlag {
            showModel(true)
            didShowModel(isFirstTime: flag.isModelDidShowFirstTimeInvalid)
            flag.isModelDidShowFirstTimeInvalid = false
        }
        
        if showEmptyFlag {
            showEmpty(true)
        }
        
        if showErrorFlag {
            showEmpty(true)
        }
        
        if showLoadingFlag {
            showLoading(true)
        }
    }
    
    
    
    
    
    func didRefreshModel() {
        
    }
    
    func willLoadModel() {
        
    }
    
    func didLoadModel(isFirstTime: Bool) {
        
    }
    
    func didShowModel(isFirstTime: Bool) {
        
    }
    
    func showModel(_ show: Bool) {
        
    }
    
    func showEmpty(_ show: Bool) {
        
    }
    
    func showError(_ show: Bool) {
        if show {
            if model.isLoaded || !canShowModel() {
                if errorView == nil {
                    errorView = StateView(title: DefaultConfig.Text.error, image: DefaultConfig.Image.error)
                    errorView?.frame = CGRect(x: 0, y: topOffset, width: view.width, height: view.height - topOffset)
                    errorView?.add(target: self, selector: #selector(reloadFromErrorButton))
                } else {
                    view.bringSubview(toFront: errorView!)
                }
            }
            if let error = modelError as NSError?, error.code == NSURLErrorNotConnectedToInternet { // 由于无网络造成的失败
                errorView?.bind(title: DefaultConfig.Text.noNetwork, image: DefaultConfig.Image.noNetwork)
            } else {
                errorView?.bind(title: DefaultConfig.Text.error, image: DefaultConfig.Image.error)
            }
        } else {
            errorView?.removeFromSuperview()
            errorView = nil
        }
    }
    
    @objc func reloadFromErrorButton() {
        refresh()
        self .showError(false)
        modelError = nil
        model.load(more: false)
    }
    
    // MARK: - DataModelDelegateCompatible
    open func dataModel(didStartLoad model: DataModelCompatible) {
        if model === _model {
            flag.isModelWillLoadInvalid = true
            flag.isModelDidLoadFirstTimeInvalid = true
            invalidateView()
            
            if isShowDefaultLoadingStates {
                showLoading(true)
            }
        }
    }
    
    open func dataModel(_ model: DataModelCompatible, didFinishLoad data: Any?) {
        if model === _model {
            didFinishLoad(data: data)
            modelError = nil
            flag.isModelDidLoadInvalid = true
            invalidateView()
            
            if isShowDefaultLoadingStates {
                showLoading(false)
                showError(false)
            }
        }
    }
    
    open func dataModel(_ model: DataModelCompatible, didFailLoad error: Error) {
        if model === _model {
            modelError = error
            didFailedLoad(error: error)
        }
        
        if isShowDefaultLoadingStates {
            showLoading(false)
            showError(false)
        }
    }
    
    open func dataModel(didCancelLoad model: DataModelCompatible) {
        if model === _model {
            invalidateView()
        }
    }
    
    open func dataModel(didChange model: DataModelCompatible) {
        if model === _model {
            refresh()
        }
    }
    
    open func didFinishLoad(data: Any?) {}
    open func didFailedLoad(error: Error?) {}
    
    
}
